package com.apes.crm.masterControl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.soe.metadata.BusinessType;
import com.apes.framework.plugin.soe.store.database.service.BusinessTypeService;
import com.apes.framework.plugin.todo.TodoTaskService;
import com.apes.framework.plugin.workflow.FlowableEngine;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @Title: customerControlService
 * @Description: 部门总控中心
 * @author: ZhengZeXian
 * @create: 2021/1/26 11:10
 */
@Service("customerControlService")
@SuppressWarnings("all")
public class customerControlService extends DomainService{

    @Autowired
    TodoTaskService todoTaskService;
    @Autowired
    UserRepository userRepository;
    @Autowired
    FlowableEngine flowableEngine;
    @Autowired
    customerControlDao customerControlDao;
    @Autowired
    EnumerationRepository enumerationRepository;
    @Autowired
    DeptRepository deptRepository;
    @Autowired
    BusinessTypeService businessTypeService;

    /**
     * OA 发起部门 为 行政部门Branch
     * OA 为经办
     * TODO 待办 发起部门 为 业务部门Dept 通过行政部门找对应的业务部门
     * TODO Tags 字段区分 经办和督办
     * enumerationTypeId 枚举编码 ECC001 客服中心
     * toDoType 类型：1、经办 2、督办 3、发起
     * 经办督办都是通过部门找人,人找到具体待办事项
     */

    /**
     * 获取所有待办数据
     * @param request branchId 行政部门编码
     * @return
     */
    public List<Map<String, List>> findAll(SimpleRequest request){
        List<Map<String, List>> returnData =new ArrayList<>();

        //新增门店总控 条件二选一 门店总控（使用业务编码调用） 和 部门总控 （使用枚举调用）
        Map map = request.getMap();
        String enumerationTypeId = (String) map.get("enumeration_type_id");
        String deptId = (String) map.get("dept_id");

        String type = (String) map.get("toDoType");

        //获取行政部门列表
        List<String> branchIds = new ArrayList<>();

        if(enumerationTypeId != null){
            //查找枚举类型
            List<Enumeration> enumerations = enumerationRepository.findByType(enumerationTypeId);
            enumerations.forEach(e -> branchIds.add(e.getCode()));
        }else{
            Dept dept = deptRepository.findOne(deptId);
            branchIds.add(dept.getBranch().getId());
        }
//        branchIds.add("6194R001"); //部门测试

        if ("发起".equals(type)){
            List<Map<String, List>> oaInitiateData = getOAInitiateData(branchIds);//获取OA数据
            List<Map<String, List>> todoInitiateData = getTodoInitiateData(branchIds);  //获取待办数据
            if (oaInitiateData != null) returnData.addAll(oaInitiateData);
            if (todoInitiateData != null) returnData.addAll(todoInitiateData);
            return returnData;
        }

        //经办督办需要根据行政部门找到对应人员找数据
        List<User> users = userRepository.findByBranch(branchIds);
        List<Map> taskMaps = new ArrayList<>();     //存待办
        List<String> userIds = new ArrayList<>();       //存OA
        if (!users.isEmpty()){
            users.stream().forEach(user -> {
                String userId = String.valueOf(user.getId());
                List<Map> todoTasks = todoTaskService.todoListFilters(checkCondition(userId,type));
                if (todoTasks != null) taskMaps.addAll(todoTasks);
                userIds.add(userId);    //存人员ID
            });
        }

        //待办
        if (taskMaps != null){} returnData.addAll(formatTodoData(taskMaps));

        //OA都是经办
        if ("经办".equals(type)){
            if (!users.isEmpty()) {
                JSONObject param = new JSONObject();
                param.put("users",userIds);
                param.put("finished",0);
                List<Map> maps = customerControlDao.queryOAByParam(param);
                if (maps != null) returnData.addAll(formatOAData(maps));
            }
        }

        return returnData;
    }

    /**
     * 根据单据类型单据状态获取待办列表（抽屉）
     * @param request
     * @return
     */
    public List<Map> findByDocumentType(SimpleRequest request){
        Map data = request.getMap();
        String toDoType = (String) data.get("toDoType");  //待办类型
        String documentType = (String) data.get("documentType");  //单据类型
        String statusName = (String) data.get("statusName");      //单据状态

        //门店总控（使用业务编码调用） 和 部门总控 （使用枚举调用）
        String enumerationTypeId = (String) data.get("enumeration_type_id");  //枚举类型
        String deptId = (String) data.get("dept_id");

        //获取行政部门列表
        List<String> branchIds = new ArrayList<>();

        //根据枚举ID和业务编码分流
        if(enumerationTypeId != null){
            List<Enumeration> enumerations = enumerationRepository.findByType(enumerationTypeId);
            enumerations.forEach(e -> branchIds.add(e.getCode()));
        }else {
            Dept dept = deptRepository.findOne(deptId);
            branchIds.add(dept.getBranch().getId());
        }
//        branchIds.add("6194R001");部门测试

        List<User> users = userRepository.findByBranch(branchIds);
        List<String> userIds = new ArrayList<>();
        if (users != null) users.forEach(user -> userIds.add(String.valueOf(user.getId())));

        //返回数据
        List<Map> returnData = new ArrayList<>();

        if ("发起".equals(toDoType)){
            JSONObject param = new JSONObject();
            param.put("processInitiatingDepartment",branchIds);  //发起部门列表
            param.put("name",documentType);         //单据类型
            param.put("curTaskName",statusName);    //单据状态
            param.put("finished",0);
            List<Map> oaMaps = customerControlDao.queryOAByParam(param);
            if (oaMaps != null) {
                oaMaps.stream().forEach(oa -> {
                    //根据OA的taskId(任务ID)获取数据
                    Map task = flowableEngine.getTaskByTaskId(oa.get("TASKID").toString());
                    returnData.add(task);
                });
            }
            List<Map> todoMaps = todoTaskService.todoListByBranchAndBusiness(branchIds, documentType, statusName);
            if (todoMaps != null){
                todoMaps = todoMaps.stream().filter(distinctByKey(b -> b.get("businessKey"))).collect(Collectors.toList());  //根据businessKey 业务单号 去重
                returnData.addAll(todoMaps);
            }
            return returnData;
        }

        //获取待办（经办，督办）
        List<Map> todoMaps = todoTaskService.todoListFilters(checkCondition3(userIds, toDoType, documentType, statusName));
        if (todoMaps != null){
            todoMaps = todoMaps.stream().filter(distinctByKey(b -> b.get("businessKey"))).collect(Collectors.toList());  //根据businessKey 业务单号 去重
            returnData.addAll(todoMaps);
        }

        //OA属于经办
        if ("经办".equals(toDoType)){
            JSONObject param = new JSONObject();
            param.put("users",userIds);
            param.put("name",documentType);
            param.put("curTaskName",statusName);
            param.put("finished",0);
            //根据用户ID 单据类型 单据名称 完结状态 查找符合条件的OA
            List<Map> maps = customerControlDao.queryOAByParam(param);
            if (maps != null){
                maps.stream().forEach(map ->{
                    //根据OA的taskId(任务ID)获取数据
                    Map task = flowableEngine.getTaskByTaskId(map.get("TASKID").toString());
                    returnData.add(task);
                });
            }
        };

        return returnData;
    }

    /**
     * 计算超时数
     * @param list
     * @return 超时数量
     */
    public String checkTimeOut(List<Map> list){
        Date date = new Date();
        //filter里返回true为不过滤
        list = list.parallelStream().filter(item -> {
            Date expired = (Date) item.get("expired");
            //当expired小于date时，返回true，当大于等于时，返回false  在某个时间之前
            if (expired == null) return false;
            return expired.before(date);
        }).collect(Collectors.toList());
        return String.valueOf(list.size());
    }

    /**
     * 计算预警数量
     * @param list
     * @return 超时数量
     */
    public String checkWarning(List<Map> list){
        Date date = new Date();
        //filter里返回true为不过滤
        list = list.parallelStream().filter(item -> {
            Date expired = (Date) item.get("expired");
//            expired.setTime(expired.getTime() + 3*60*1000); //在当前时间基础上增加3分钟
            //TODO 暂时定义预警时间为3分钟内
            if (expired == null) return false;
            long between = ChronoUnit.MINUTES.between(Instant.ofEpochMilli(expired.getTime()), Instant.ofEpochMilli(date.getTime()));
            return  between >= 0 && between <= 3 ? true : false;
        }).collect(Collectors.toList());
        return String.valueOf(list.size());
    }

    /**
     * 获取OA发起部门数据
     * @param branchId 行政部门编码
     * @return OA前端响应格式数据
     */
    public List<Map<String, List>> getOAInitiateData(List<String> branchIds){
        List<Map<String, List>> returnData = new ArrayList<>();
        //根据发起部门查询对应的OA
        JSONObject param = new JSONObject();
        param.put("processInitiatingDepartment",branchIds);
        param.put("finished",0);
        List<Map> queryOA = customerControlDao.queryOAByParam(param);
        if (queryOA != null) returnData.addAll(formatOAData(queryOA));
        return returnData;
    }

    /**
     * 根据发起部门查找对应待办数据
     * @param branchId 行政部门
     * @return
     */
    public List<Map<String, List>> getTodoInitiateData(List<String> branchIds) {
        List<Map<String, List>> returnData = new ArrayList<>();
        List<Map> maps = todoTaskService.todoListByBranch(branchIds);
        if (maps != null){
//            maps = maps.stream().filter(distinctByKey(b -> b.get("businessKey"))).collect(Collectors.toList());  //根据businessKey 业务单号 去重
            returnData.addAll(formatTodoData(maps));
        }
        return returnData;
    }

    /**
     * 处理条件（用户编码，待办类型）
     */
    public List<Map> checkCondition(String userId , String tags){
        List<Map> filters = new ArrayList<>();
        filters.add(MapUtil.mapper("field","userId","operator","EQ","value",userId));
        filters.add(MapUtil.mapper("field","tags","operator","EQ","value",tags));
        return filters;
    }

    /**
     * 处理条件（发起部门）
     */
    public List<Map> checkCondition2(String deptId){
        List<Map> filters = new ArrayList<>();
        filters.add(MapUtil.mapper("field","initDeptId","operator","EQ","value",deptId));
        return filters;
    }

    /**
     * 处理条件（用户编码，待办类型，单据类型，单据状态）
     */
    public List<Map> checkCondition3(List<String> userId , String tags , String documentType,String statusName){
        List<Map> filters = new ArrayList<>();
        filters.add(MapUtil.mapper("field","userId","operator","IN","value",userId));
        filters.add(MapUtil.mapper("field","tags","operator","EQ","value",tags));
        filters.add(MapUtil.mapper("field","aggregateType","operator","EQ","value",documentType));
        filters.add(MapUtil.mapper("field","description","operator","EQ","value",statusName));
        return filters;
    }

    /**
     * 处理条件（发起部门,单据类型，单据状态）
     */
    public List<Map> checkCondition4(String deptId, String documentType,String statusName){
        List<Map> filters = new ArrayList<>();
        filters.add(MapUtil.mapper("field","initDeptId","operator","EQ","value",deptId));
        filters.add(MapUtil.mapper("field","aggregateType","operator","EQ","value",documentType));
        filters.add(MapUtil.mapper("field","description","operator","EQ","value",statusName));
        return filters;
    }

    /**
     * 处理待办数据格式化为前端响应数据格式
     * @param maps 待办数据
     * @return
     */
    public List<Map<String, List>> formatTodoData(List<Map> maps){
       List<Map<String, List>> returnData = new ArrayList<>();
       //根据businessKey 业务单号 去重
       maps = maps.stream().filter(distinctByKey(b -> b.get("businessKey"))).collect(Collectors.toList());
        //待办根据单据类型分组
       Map<Object, List<Map>> listMap = maps.stream().collect(Collectors.groupingBy(d -> d.get("businessTypeName")));
       for (Map.Entry<Object, List<Map>> entry : listMap.entrySet()) {
           List<Map> temp = new ArrayList();
           //根据描述分组就是单据状态 例：待提交方案
           Map<Object, List<Map>> description = entry.getValue().stream().collect(Collectors.groupingBy(e -> e.get("description")));
           for (Map.Entry<Object, List<Map>> entry2 : description.entrySet()) {
               temp.add(MapUtil.mapper(
                   "statusName",entry2.getKey(),//单据状态
                       "summary",entry2.getValue().size(),//取当前单据状态总数
                       "timeOut",checkTimeOut(entry2.getValue()),//超时数
                       "warning",checkWarning(entry2.getValue()))//预警数
               );
           }
           returnData.add(
               MapUtil.mapper(
               "documentTypeName",entry.getKey(),   //单据类型名称
                      "documentType",entry.getValue().get(0).get("businessType"), //单据类型
               "list",temp
           ));
       }
       return returnData;
    }

    /**
     * 处理OA数据格式化为前端响应格式
     * @param maps OA数据
     * @return
     */
    public List<Map<String, List>> formatOAData(List<Map> maps) {
        List<Map<String, List>> returnData = new ArrayList<>();
        //根据单据类型分组
        Map<Object, List<Map>> collect = maps.stream().collect(Collectors.groupingBy(d -> d.get("NAME")));
        for (Map.Entry<Object, List<Map>> entry : collect.entrySet()) {
            List<Map> list = new ArrayList();
            //根据单据类型里面的单据状态分组
            Map<Object, List<Map>> curtasks = entry.getValue().stream().collect(Collectors.groupingBy(e -> e.get("CURTASKNAME")));
            for (Map.Entry<Object, List<Map>> entry1 : curtasks.entrySet()) {
                list.add(MapUtil.mapper(
                        "statusName",entry1.getKey(),//单据状态
                        "summary",entry1.getValue().size(),//取当前单据状态总数
                        "timeOut","0",      //超时数
                        "warning","0"       //预警数
                ));
            }
            returnData.add(MapUtil.mapper(
                    "documentTypeName", entry.getKey(), //单据类型名称
                    "documentType",entry.getKey(), //单据类型
                    "list",list
            ));
        }
        return returnData;
    }

        /**
         * 根据map里的某个key值去重
         * @param keyExtractor
         * @param <T>
         * @return
         */
    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Boolean> seen = new ConcurrentHashMap<>(); return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 查询需签合同人员
     */
    public List<Map> needContract(SimpleRequest request){
        List<Map> needContract = customerControlDao.queryNeedContract(new JSONObject());
        Map<Object, List<Map>> collect = needContract.stream().collect(Collectors.groupingBy(d -> d.get("OPERATION")));
        return disposeContract(collect);
    }

    /**
     * 查询需签合同人员 根据运营模式
     */
    public Map needContractItem(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONObject data = jo.getJSONObject("data"); // 表单数据
        String lefttext = data.getString("LEFTTEXT");
        List<Map> maps = customerControlDao.queryNeedContract(disposeOperation(lefttext));
        JSONArray objects = toJSONArray(maps);
        return MapUtil.mapper(
                "content", objects,
                "total", objects.size(),
                "size",  objects.size()
        );
    }

    /**
     * 查询续签合同人员
     */
    public List<Map> renewContract(SimpleRequest request){
        List<Map> renewContract = customerControlDao.queryRenewContract(new JSONObject());
        Map<Object, List<Map>> collect = renewContract.stream().collect(Collectors.groupingBy(d -> d.get("OPERATION")));
        return disposeContract(collect);
    }

    /**
     * 查询续签合同人员 根据运营模式
     */
    public Map renewContractItem(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONObject data = jo.getJSONObject("data"); // 表单数据
        String lefttext = data.getString("LEFTTEXT");
        List<Map> maps = customerControlDao.queryRenewContract(disposeOperation(lefttext));
        JSONArray objects = toJSONArray(maps);
        return MapUtil.mapper(
                "content", objects,
                "total", objects.size(),
                "size",  objects.size()
        );
    }

    /**
     * 处理合同返回前端展示数据
     * @param collect 根据运营模式分组后的数据
     * @return
     */
    public List<Map> disposeContract(Map<Object, List<Map>> collect){
        List<Map> returnData = new ArrayList<>();
        for (Map.Entry<Object, List<Map>> entry : collect.entrySet()) {
            returnData.add(MapUtil.mapper(
                    "LEFTTEXT",entry.getKey(),
                    "RIGHTTEXT",entry.getValue().size()
            ));
        }
        return returnData;
    }

    /***
     * 功能： 用于处理返回值
     * @param lists
     * @return
     */
    protected JSONArray toJSONArray(List<Map> lists) {
        JSONArray returnArr = new JSONArray();
        lists.stream().forEach(list -> returnArr.add(new JSONObject(list)));
        return returnArr;
    }

    /**
     * 处理运营模式 封装成查询要用的 JSONObject
     * @param operation
     * @return
     */
    private JSONObject disposeOperation(String operation){
        JSONObject param = new JSONObject();
        List<String> list = new ArrayList<>();
        if (operation.equals("直营")){
            list.add("001072");
        }else if(operation.equals("赋能店")){
            list.add("001073");
        }else {
            list.add("001071");
        }
        param.put("OPERATION_ID",list);
        return param;
    }

}
